/*     */ package com.zimbra.cs.datasource;
/*     */ 
/*     */ import com.zimbra.common.calendar.ICalTimeZone;
/*     */ import com.zimbra.common.calendar.TimeZoneMap;
/*     */ import com.zimbra.common.calendar.ZCalendar.ICalTok;
/*     */ import com.zimbra.common.calendar.ZCalendar.ZCalendarBuilder;
/*     */ import com.zimbra.common.calendar.ZCalendar.ZComponent;
/*     */ import com.zimbra.common.calendar.ZCalendar.ZProperty;
/*     */ import com.zimbra.common.calendar.ZCalendar.ZVCalendar;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.Pair;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.DataSource;
/*     */ import com.zimbra.cs.dav.DavElements;
/*     */ import com.zimbra.cs.dav.DavException;
/*     */ import com.zimbra.cs.dav.client.CalDavClient;
/*     */ import com.zimbra.cs.dav.client.CalDavClient.Appointment;
/*     */ import com.zimbra.cs.dav.client.DavObject;
/*     */ import com.zimbra.cs.dav.client.DavRequest;
/*     */ import com.zimbra.cs.db.DbDataSource;
/*     */ import com.zimbra.cs.db.DbDataSource.DataSourceItem;
/*     */ import com.zimbra.cs.mailbox.CalendarItem;
/*     */ import com.zimbra.cs.mailbox.Flag;
/*     */ import com.zimbra.cs.mailbox.Folder;
/*     */ import com.zimbra.cs.mailbox.Folder.FolderOptions;
/*     */ import com.zimbra.cs.mailbox.MailItem;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.Mailbox.SetCalendarItemData;
/*     */ import com.zimbra.cs.mailbox.Metadata;
/*     */ import com.zimbra.cs.mailbox.OperationContext;
/*     */ import com.zimbra.cs.mailbox.calendar.Invite;
/*     */ import com.zimbra.cs.mailbox.util.TypedIdList;
/*     */ import com.zimbra.soap.type.DataSource.ConnectionType;
/*     */ import java.io.CharArrayWriter;
/*     */ import java.io.IOException;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collection;
/*     */ import java.util.HashMap;
/*     */ import java.util.HashSet;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class CalDavDataImport
/*     */   extends MailItemImport
/*     */ {
/*     */   private static final String METADATA_KEY_TYPE = "t";
/*     */   private static final String METADATA_TYPE_FOLDER = "f";
/*     */   private static final String METADATA_TYPE_APPOINTMENT = "a";
/*     */   private static final String METADATA_KEY_ETAG = "e";
/*     */   private static final String METADATA_KEY_CTAG = "c";
/*  66 */   private static final int DEFAULT_FOLDER_FLAGS = Flag.BITMASK_CHECKED;
/*     */   private CalDavClient mClient;
/*     */   
/*     */   private static class CalendarFolder {
/*     */     public int id;
/*     */     public Folder folder;
/*     */     public boolean ctagMatched;
/*     */     
/*  74 */     public CalendarFolder(int fid) { this.id = fid; }
/*     */   }
/*     */   
/*     */   public CalDavDataImport(DataSource ds) throws ServiceException {
/*  78 */     super(ds);
/*     */   }
/*     */   
/*     */   public void importData(List<Integer> folderIds, boolean fullSync) throws ServiceException
/*     */   {
/*  83 */     ArrayList<CalendarFolder> folders = new ArrayList();
/*     */     try {
/*  85 */       this.mbox.beginTrackingSync();
/*  86 */       Iterator i$; if (folderIds != null)
/*  87 */         for (i$ = folderIds.iterator(); i$.hasNext();) { int fid = ((Integer)i$.next()).intValue();
/*  88 */           folders.add(new CalendarFolder(fid));
/*     */         } else
/*  90 */         folders = syncFolders();
/*  91 */       octxt = new OperationContext(this.mbox);
/*  92 */       for (CalendarFolder f : folders) {
/*  93 */         f.folder = this.mbox.getFolderById(octxt, f.id);
/*  94 */         if (f.folder.getDefaultView() == MailItem.Type.APPOINTMENT)
/*  95 */           sync(octxt, f);
/*     */       }
/*     */     } catch (DavException e) {
/*     */       OperationContext octxt;
/*  99 */       throw ServiceException.FAILURE("error importing CalDAV data", e);
/*     */     } catch (IOException e) {
/* 101 */       throw ServiceException.FAILURE("error importing CalDAV data", e);
/*     */     }
/*     */   }
/*     */   
/*     */   public void test() throws ServiceException
/*     */   {
/* 107 */     this.mClient = new CalDavClient(getTargetUrl());
/* 108 */     this.mClient.setAppName(getAppName());
/* 109 */     this.mClient.setCredential(getUsername(), getDecryptedPassword());
/* 110 */     this.mClient.setDebugEnabled(this.dataSource.isDebugTraceEnabled());
/*     */     try {
/* 112 */       this.mClient.login(getDefaultPrincipalUrl());
/*     */     } catch (Exception x) {
/* 114 */       throw ServiceException.FAILURE(x.getMessage(), x);
/*     */     }
/*     */   }
/*     */   
/*     */   protected String getUsername() {
/* 119 */     return getDataSource().getUsername();
/*     */   }
/*     */   
/*     */   protected String getDecryptedPassword() throws ServiceException {
/* 123 */     return getDataSource().getDecryptedPassword();
/*     */   }
/*     */   
/* 126 */   protected byte getDefaultColor() { return 0; }
/*     */   
/*     */   protected String getDefaultPrincipalUrl() {
/* 129 */     DataSource ds = getDataSource();
/* 130 */     String[] attrs = ds.getMultiAttr("zimbraDataSourceAttribute");
/* 131 */     for (String a : attrs) {
/* 132 */       if (a.startsWith("p:")) {
/* 133 */         return a.substring(2).replaceAll("_USERNAME_", getUsername());
/*     */       }
/*     */     }
/* 136 */     return null;
/*     */   }
/*     */   
/*     */   protected String getTargetUrl() {
/* 140 */     DataSource ds = getDataSource();
/* 141 */     DataSource.ConnectionType ctype = ds.getConnectionType();
/* 142 */     StringBuilder url = new StringBuilder();
/*     */     
/* 144 */     switch (ctype) {
/*     */     case ssl: 
/* 146 */       url.append("https://");
/* 147 */       break;
/*     */     case cleartext: 
/*     */     default: 
/* 150 */       url.append("http://");
/*     */     }
/*     */     
/* 153 */     url.append(ds.getHost()).append(":").append(ds.getPort());
/* 154 */     return url.toString();
/*     */   }
/*     */   
/*     */   protected String getAppName() {
/* 158 */     return "ZCS";
/*     */   }
/*     */   
/*     */   private CalDavClient getClient() throws ServiceException, IOException, DavException {
/* 162 */     if (this.mClient == null) {
/* 163 */       this.mClient = new CalDavClient(getTargetUrl());
/* 164 */       this.mClient.setAppName(getAppName());
/* 165 */       this.mClient.setCredential(getUsername(), getDecryptedPassword());
/* 166 */       this.mClient.setDebugEnabled(this.dataSource.isDebugTraceEnabled());
/* 167 */       this.mClient.login(getDefaultPrincipalUrl());
/*     */     }
/* 169 */     return this.mClient;
/*     */   }
/*     */   
/* 172 */   private static enum Status { created,  deleted,  modified;
/*     */     
/*     */     private Status() {} }
/*     */   
/*     */   private static class RemoteItem { CalDavDataImport.Status status; }
/* 177 */   private static class RemoteCalendarItem extends CalDavDataImport.RemoteItem { public RemoteCalendarItem(String h, String e) { super();this.href = h;this.etag = e;
/*     */     }
/*     */     
/*     */     String href;
/*     */     String etag;
/*     */     int itemId;
/*     */   }
/*     */   
/*     */   protected int getRootFolderId(DataSource ds) throws ServiceException
/*     */   {
/* 187 */     return ds.getFolderId();
/*     */   }
/*     */   
/*     */   protected HashMap<String, DbDataSource.DataSourceItem> getAllFolderMappings(DataSource ds) throws ServiceException {
/* 191 */     Collection<DbDataSource.DataSourceItem> allFolders = DbDataSource.getAllMappingsInFolder(ds, getRootFolderId(ds));
/* 192 */     HashMap<String, DbDataSource.DataSourceItem> folders = new HashMap();
/* 193 */     for (DbDataSource.DataSourceItem f : allFolders)
/* 194 */       if (f.remoteId != null)
/* 195 */         folders.put(f.remoteId, f);
/* 196 */     return folders;
/*     */   }
/*     */   
/*     */   private ArrayList<CalendarFolder> syncFolders() throws ServiceException, IOException, DavException {
/* 200 */     ArrayList<CalendarFolder> ret = new ArrayList();
/* 201 */     DataSource ds = getDataSource();
/* 202 */     OperationContext octxt = new OperationContext(this.mbox);
/* 203 */     HashMap<String, DbDataSource.DataSourceItem> allFolders = getAllFolderMappings(ds);
/* 204 */     Folder rootFolder = null;
/*     */     try {
/* 206 */       rootFolder = this.mbox.getFolderById(octxt, getRootFolderId(ds));
/*     */     }
/*     */     catch (MailServiceException.NoSuchItemException e) {
/* 209 */       ZimbraLog.datasource.info("Folder %d was deleted.  Deleting data source %s.", new Object[] { Integer.valueOf(getRootFolderId(ds)), ds.getName() });
/*     */       
/* 211 */       this.mbox.getAccount().deleteDataSource(ds.getId());
/*     */       
/* 213 */       return new ArrayList(0);
/*     */     }
/* 215 */     List<Integer> deleted = new ArrayList();
/* 216 */     int lastSync = (int)rootFolder.getLastSyncDate();
/* 217 */     Iterator i$; if (lastSync > 0)
/* 218 */       for (i$ = this.mbox.getTombstones(lastSync).getAllIds().iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 219 */         deleted.add(Integer.valueOf(itemId));
/*     */       }
/* 221 */     CalDavClient client = getClient();
/* 222 */     Map<String, DavObject> calendars = client.getCalendars();
/* 223 */     for (String name : calendars.keySet()) {
/* 224 */       DavObject obj = (DavObject)calendars.get(name);
/* 225 */       String ctag = obj.getPropertyText(DavElements.E_GETCTAG);
/* 226 */       String url = obj.getHref();
/* 227 */       DbDataSource.DataSourceItem f = (DbDataSource.DataSourceItem)allFolders.get(url);
/* 228 */       if (f == null)
/* 229 */         f = new DbDataSource.DataSourceItem(0, 0, url, null);
/* 230 */       CalendarFolder cf = new CalendarFolder(f.itemId);
/* 231 */       Folder folder = null;
/* 232 */       if (f.itemId != 0)
/*     */       {
/* 234 */         if (deleted.contains(Integer.valueOf(f.itemId))) {
/* 235 */           allFolders.remove(url);
/* 236 */           DbDataSource.deleteMapping(ds, f.itemId);
/* 237 */           DbDataSource.deleteAllMappingsInFolder(ds, f.itemId);
/* 238 */           deleteRemoteFolder(url);
/* 239 */           continue;
/*     */         }
/*     */         try
/*     */         {
/* 243 */           folder = this.mbox.getFolderById(octxt, f.itemId);
/*     */         } catch (ServiceException se) {
/* 245 */           if (se.getCode() != "mail.NO_SUCH_FOLDER") {
/* 246 */             throw se;
/*     */           }
/* 248 */           f.itemId = 0;
/*     */         }
/*     */       }
/* 251 */       if (f.itemId == 0)
/*     */       {
/*     */         try {
/* 254 */           folder = this.mbox.getFolderByName(octxt, rootFolder.getId(), name);
/* 255 */           if (folder.getDefaultView() != MailItem.Type.APPOINTMENT) {
/* 256 */             name = name + " (" + getDataSource().getName() + ")";
/* 257 */             folder = null;
/*     */           }
/*     */         }
/*     */         catch (MailServiceException.NoSuchItemException e) {}
/*     */         
/* 262 */         if (folder == null) {
/* 263 */           Folder.FolderOptions fopt = new Folder.FolderOptions();
/* 264 */           fopt.setDefaultView(MailItem.Type.APPOINTMENT).setFlags(DEFAULT_FOLDER_FLAGS).setColor(getDefaultColor());
/* 265 */           folder = this.mbox.createFolder(octxt, name, rootFolder.getId(), fopt);
/*     */         }
/* 267 */         f.itemId = folder.getId();
/* 268 */         f.folderId = folder.getFolderId();
/* 269 */         f.md = new Metadata();
/* 270 */         f.md.put("t", "f");
/* 271 */         if (ctag != null) {
/* 272 */           f.md.put("c", ctag);
/*     */         }
/* 274 */         f.remoteId = url;
/* 275 */         cf.id = f.itemId;
/* 276 */         this.mbox.setSyncDate(octxt, folder.getId(), this.mbox.getLastChangeID());
/* 277 */         DbDataSource.addMapping(ds, f);
/* 278 */       } else if (f.md == null) {
/* 279 */         ZimbraLog.datasource.warn("syncFolders: empty metadata for item %d", new Object[] { Integer.valueOf(f.itemId) });
/* 280 */         f.folderId = folder.getFolderId();
/* 281 */         f.remoteId = url;
/* 282 */         f.md = new Metadata();
/* 283 */         f.md.put("t", "f");
/* 284 */         if (ctag != null)
/* 285 */           f.md.put("c", ctag);
/* 286 */         DbDataSource.addMapping(ds, f);
/* 287 */       } else if (ctag != null) {
/* 288 */         String oldctag = f.md.get("c", null);
/* 289 */         if (ctag.equals(oldctag)) {
/* 290 */           cf.ctagMatched = true;
/*     */         } else {
/* 292 */           f.md.put("c", ctag);
/* 293 */           DbDataSource.updateMapping(ds, f);
/*     */         }
/*     */       }
/* 296 */       String fname = folder.getName();
/* 297 */       if (!fname.equals(name)) {
/* 298 */         ZimbraLog.datasource.warn("renaming folder %s to %s", new Object[] { fname, name });
/*     */         try {
/* 300 */           this.mbox.rename(octxt, f.itemId, MailItem.Type.FOLDER, name, folder.getFolderId());
/*     */         } catch (ServiceException e) {
/* 302 */           ZimbraLog.datasource.warn("folder rename failed", e);
/*     */         }
/*     */       }
/* 305 */       allFolders.remove(url);
/* 306 */       ret.add(cf);
/*     */     }
/* 308 */     if (!allFolders.isEmpty())
/*     */     {
/* 310 */       ArrayList<Integer> fids = new ArrayList();
/* 311 */       int[] fidArray = new int[allFolders.size()];
/* 312 */       int i = 0;
/* 313 */       for (DbDataSource.DataSourceItem f : allFolders.values()) {
/* 314 */         Folder folder = this.mbox.getFolderById(octxt, f.itemId);
/* 315 */         if ((folder == null) || (folder.getDefaultView() == MailItem.Type.APPOINTMENT) || (folder.getDefaultView() == MailItem.Type.TASK))
/*     */         {
/*     */ 
/*     */ 
/* 319 */           fids.add(Integer.valueOf(f.itemId));
/* 320 */           fidArray[(i++)] = f.itemId;
/* 321 */           DbDataSource.deleteAllMappingsInFolder(ds, f.itemId);
/*     */         } }
/* 323 */       if (!fids.isEmpty()) {
/* 324 */         DbDataSource.deleteMappings(ds, fids);
/*     */         try {
/* 326 */           this.mbox.delete(octxt, fidArray, MailItem.Type.FOLDER, null);
/*     */         } catch (ServiceException e) {
/* 328 */           ZimbraLog.datasource.warn("folder delete failed", e);
/*     */         }
/*     */       }
/*     */     }
/* 332 */     this.mbox.setSyncDate(octxt, rootFolder.getId(), this.mbox.getLastChangeID());
/* 333 */     return ret;
/*     */   }
/*     */   
/* 336 */   private void deleteRemoteFolder(String url) throws ServiceException, IOException, DavException { ZimbraLog.datasource.debug("deleteRemoteFolder: deleting remote folder %s", new Object[] { url });
/* 337 */     getClient().sendRequest(DavRequest.DELETE(url));
/*     */   }
/*     */   
/* 340 */   private boolean pushDelete(Collection<Integer> itemIds) throws ServiceException { DataSource ds = getDataSource();
/* 341 */     boolean deleted = false;
/* 342 */     ArrayList<Integer> toDelete = new ArrayList();
/* 343 */     for (Iterator i$ = itemIds.iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/*     */       try {
/* 345 */         deleteRemoteItem(DbDataSource.getMapping(ds, itemId));
/* 346 */         toDelete.add(Integer.valueOf(itemId));
/*     */       } catch (Exception e) {
/* 348 */         ZimbraLog.datasource.warn("pushDelete: can't delete remote item for item " + itemId, e);
/*     */       }
/*     */     }
/* 351 */     if (toDelete.size() > 0) {
/* 352 */       DbDataSource.deleteMappings(ds, toDelete);
/* 353 */       deleted = true;
/*     */     }
/* 355 */     return deleted;
/*     */   }
/*     */   
/* 358 */   private void deleteRemoteItem(DbDataSource.DataSourceItem item) throws ServiceException, IOException, DavException { if ((item.itemId <= 0) || (item.md == null)) {
/* 359 */       ZimbraLog.datasource.warn("pushDelete: empty item %d", new Object[] { Integer.valueOf(item.itemId) });
/* 360 */       return;
/*     */     }
/* 362 */     String type = item.md.get("t", null);
/* 363 */     if ((type == null) || (!type.equals("a")))
/*     */     {
/* 365 */       return;
/*     */     }
/* 367 */     String uri = item.remoteId;
/* 368 */     if (uri == null) {
/* 369 */       ZimbraLog.datasource.warn("pushDelete: empty uri for item %d", new Object[] { Integer.valueOf(item.itemId) });
/* 370 */       return;
/*     */     }
/* 372 */     if ("f".equals(type)) {
/* 373 */       ZimbraLog.datasource.debug("pushDelete: deleting remote folder %s", new Object[] { uri });
/* 374 */       getClient().sendRequest(DavRequest.DELETE(uri));
/* 375 */     } else if ("a".equals(type)) {
/* 376 */       ZimbraLog.datasource.debug("pushDelete: deleting remote appointment %s", new Object[] { uri });
/* 377 */       getClient().sendRequest(DavRequest.DELETE(uri));
/*     */     } else {
/* 379 */       ZimbraLog.datasource.warn("pushDelete: unrecognized item type for %d: %s", new Object[] { Integer.valueOf(item.itemId), type });
/*     */     }
/*     */   }
/*     */   
/* 383 */   private String createTargetUrl(MailItem mitem) throws ServiceException { DbDataSource.DataSourceItem folder = DbDataSource.getMapping(getDataSource(), mitem.getFolderId());
/* 384 */     String url = folder.remoteId;
/* 385 */     switch (mitem.getType()) {
/*     */     case APPOINTMENT: 
/* 387 */       url = url + ((CalendarItem)mitem).getUid() + ".ics";
/* 388 */       break;
/*     */     default: 
/* 390 */       String name = mitem.getName();
/* 391 */       if (name != null) {
/* 392 */         url = url + name;
/*     */       } else
/* 394 */         url = url + mitem.getSubject();
/*     */       break;
/*     */     }
/* 397 */     return url;
/*     */   }
/*     */   
/* 400 */   private void pushModify(MailItem mitem) throws ServiceException, IOException, DavException { int itemId = mitem.getId();
/* 401 */     DataSource ds = getDataSource();
/* 402 */     DbDataSource.DataSourceItem item = DbDataSource.getMapping(ds, itemId);
/* 403 */     boolean isCreate = false;
/* 404 */     if (item.remoteId == null)
/*     */     {
/* 406 */       item.md = new Metadata();
/* 407 */       item.md.put("t", "a");
/* 408 */       item.remoteId = createTargetUrl(mitem);
/* 409 */       item.folderId = mitem.getFolderId();
/* 410 */       isCreate = true;
/*     */     }
/* 412 */     String type = item.md.get("t");
/* 413 */     if ("f".equals(type)) {
/* 414 */       if (mitem.getType() != MailItem.Type.FOLDER) {
/* 415 */         ZimbraLog.datasource.warn("pushModify: item type doesn't match in metadata for item %d", new Object[] { Integer.valueOf(itemId) });
/*     */       }
/*     */       
/*     */     }
/* 419 */     else if ("a".equals(type)) {
/* 420 */       if (mitem.getType() != MailItem.Type.APPOINTMENT) {
/* 421 */         ZimbraLog.datasource.warn("pushModify: item type doesn't match in metadata for item %d", new Object[] { Integer.valueOf(itemId) });
/* 422 */         return;
/*     */       }
/*     */       
/* 425 */       ZimbraLog.datasource.debug("pushModify: sending appointment %s", new Object[] { item.remoteId });
/* 426 */       String etag = putAppointment((CalendarItem)mitem, item);
/* 427 */       if (etag == null) {
/* 428 */         CalDavClient.Appointment appt = this.mClient.getEtag(item.remoteId);
/* 429 */         etag = appt.etag;
/*     */       }
/*     */       
/* 432 */       item.md.put("e", etag);
/* 433 */       if (isCreate) {
/* 434 */         DbDataSource.addMapping(ds, item);
/*     */       } else {
/* 436 */         DbDataSource.updateMapping(ds, item);
/*     */       }
/*     */     } else {
/* 439 */       ZimbraLog.datasource.warn("pushModify: unrecognized item type for %d: %s", new Object[] { Integer.valueOf(itemId), type });
/* 440 */       return;
/*     */     }
/*     */   }
/*     */   
/* 444 */   private String putAppointment(CalendarItem calItem, DbDataSource.DataSourceItem dsItem) throws ServiceException, IOException, DavException { StringBuilder buf = new StringBuilder();
/* 445 */     ArrayList<String> recipients = new ArrayList();
/*     */     
/* 447 */     buf.append("BEGIN:VCALENDAR\r\n");
/* 448 */     buf.append("VERSION:").append("2.0").append("\r\n");
/* 449 */     buf.append("PRODID:").append("Zimbra-Calendar-Provider").append("\r\n");
/* 450 */     Iterator<ICalTimeZone> iter = calItem.getTimeZoneMap().tzIterator();
/* 451 */     while (iter.hasNext()) {
/* 452 */       ICalTimeZone tz = (ICalTimeZone)iter.next();
/* 453 */       CharArrayWriter wr = new CharArrayWriter();
/* 454 */       tz.newToVTimeZone().toICalendar(wr, true);
/* 455 */       wr.flush();
/* 456 */       buf.append(wr.toCharArray());
/* 457 */       wr.close();
/*     */     }
/* 459 */     boolean appleICalExdateHack = LC.calendar_apple_ical_compatible_canceled_instances.booleanValue();
/* 460 */     ZCalendar.ZComponent[] vcomps = Invite.toVComponents(calItem.getInvites(), true, false, appleICalExdateHack);
/* 461 */     if (vcomps != null) {
/* 462 */       CharArrayWriter wr = new CharArrayWriter();
/* 463 */       for (ZCalendar.ZComponent vcomp : vcomps) {
/* 464 */         ZCalendar.ZProperty organizer = vcomp.getProperty(ZCalendar.ICalTok.ORGANIZER);
/* 465 */         if (organizer != null)
/* 466 */           organizer.setValue(getUsername());
/* 467 */         vcomp.toICalendar(wr, true);
/*     */       }
/* 469 */       wr.flush();
/* 470 */       buf.append(wr.toCharArray());
/* 471 */       wr.close();
/*     */     }
/* 473 */     buf.append("END:VCALENDAR\r\n");
/* 474 */     String etag = dsItem.md.get("e", null);
/* 475 */     if (recipients.isEmpty())
/* 476 */       recipients = null;
/* 477 */     CalDavClient.Appointment appt = new CalDavClient.Appointment(dsItem.remoteId, etag, buf.toString(), recipients);
/* 478 */     return getClient().sendCalendarData(appt);
/*     */   }
/*     */   
/* 481 */   private List<RemoteItem> getRemoteItems(Folder folder) throws ServiceException, IOException, DavException { ZimbraLog.datasource.debug("Refresh folder %s", new Object[] { folder.getPath() });
/* 482 */     DataSource ds = getDataSource();
/* 483 */     DbDataSource.DataSourceItem item = DbDataSource.getMapping(ds, folder.getId());
/* 484 */     if (item.md == null) {
/* 485 */       throw ServiceException.FAILURE("Mapping for folder " + folder.getPath() + " not found", null);
/*     */     }
/*     */     
/*     */ 
/*     */ 
/* 490 */     HashMap<String, DbDataSource.DataSourceItem> allItems = new HashMap();
/* 491 */     for (DbDataSource.DataSourceItem localItem : DbDataSource.getAllMappingsInFolder(getDataSource(), folder.getId())) {
/* 492 */       allItems.put(localItem.remoteId, localItem);
/*     */     }
/* 494 */     ArrayList<RemoteItem> ret = new ArrayList();
/* 495 */     CalDavClient client = getClient();
/* 496 */     Collection<CalDavClient.Appointment> appts = client.getEtags(item.remoteId);
/* 497 */     for (CalDavClient.Appointment a : appts) {
/* 498 */       ret.add(new RemoteCalendarItem(a.href, a.etag));
/* 499 */       allItems.remove(a.href);
/*     */     }
/* 501 */     ArrayList<Integer> deletedIds = new ArrayList();
/* 502 */     for (DbDataSource.DataSourceItem deletedItem : allItems.values())
/*     */     {
/*     */ 
/* 505 */       RemoteCalendarItem rci = new RemoteCalendarItem(deletedItem.remoteId, null);
/* 506 */       rci.status = Status.deleted;
/* 507 */       rci.itemId = deletedItem.itemId;
/* 508 */       ret.add(rci);
/* 509 */       deletedIds.add(Integer.valueOf(deletedItem.itemId));
/* 510 */       ZimbraLog.datasource.debug("deleting: %d (%s) ", new Object[] { Integer.valueOf(deletedItem.itemId), deletedItem.remoteId });
/*     */     }
/* 512 */     if (!deletedIds.isEmpty())
/* 513 */       DbDataSource.deleteMappings(ds, deletedIds);
/* 514 */     return ret;
/*     */   }
/*     */   
/* 517 */   private MailItem applyRemoteItem(RemoteItem remoteItem, Folder where) throws ServiceException, IOException { if (!(remoteItem instanceof RemoteCalendarItem)) {
/* 518 */       ZimbraLog.datasource.warn("applyRemoteItem: not a calendar item: %s", new Object[] { remoteItem });
/* 519 */       return null;
/*     */     }
/* 521 */     RemoteCalendarItem item = (RemoteCalendarItem)remoteItem;
/* 522 */     DataSource ds = getDataSource();
/* 523 */     DbDataSource.DataSourceItem dsItem = DbDataSource.getReverseMapping(ds, item.href);
/* 524 */     OperationContext octxt = new OperationContext(this.mbox);
/* 525 */     MailItem mi = null;
/* 526 */     boolean isStale = false;
/* 527 */     boolean isCreate = false;
/* 528 */     if ((dsItem.md == null) && (item.status != Status.deleted)) {
/* 529 */       dsItem.md = new Metadata();
/* 530 */       dsItem.md.put("t", "a");
/*     */     }
/* 532 */     if (dsItem.itemId == 0) {
/* 533 */       isStale = true;
/* 534 */       isCreate = true;
/*     */     } else {
/* 536 */       String etag = dsItem.md.get("e", null);
/*     */       try {
/* 538 */         mi = this.mbox.getItemById(octxt, dsItem.itemId, MailItem.Type.UNKNOWN);
/*     */       } catch (MailServiceException.NoSuchItemException se) {
/* 540 */         ZimbraLog.datasource.warn("applyRemoteItem: calendar item not found: ", new Object[] { remoteItem });
/*     */       }
/* 542 */       if (item.etag == null) {
/* 543 */         ZimbraLog.datasource.warn("No Etag returned for item %s", new Object[] { item.href });
/* 544 */         isStale = true;
/* 545 */       } else if (etag == null) {
/* 546 */         ZimbraLog.datasource.warn("Empty etag for item %d", new Object[] { Integer.valueOf(dsItem.itemId) });
/* 547 */         isStale = true;
/*     */       } else {
/* 549 */         isStale = !item.etag.equals(etag);
/*     */       }
/* 551 */       if (mi == null)
/* 552 */         isStale = true;
/*     */     }
/* 554 */     if (item.status == Status.deleted) {
/* 555 */       ZimbraLog.datasource.debug("Deleting appointment %s", new Object[] { item.href });
/*     */       try {
/* 557 */         mi = this.mbox.getItemById(octxt, item.itemId, MailItem.Type.UNKNOWN);
/*     */       } catch (MailServiceException.NoSuchItemException se) {
/* 559 */         mi = null;
/*     */       }
/*     */       try {
/* 562 */         this.mbox.delete(octxt, item.itemId, MailItem.Type.UNKNOWN);
/*     */       } catch (ServiceException se) {
/* 564 */         ZimbraLog.datasource.warn("Error deleting remotely deleted item %d (%s)", new Object[] { Integer.valueOf(item.itemId), dsItem.remoteId });
/*     */       }
/* 566 */     } else if (isStale) {
/* 567 */       ZimbraLog.datasource.debug("Updating stale appointment %s", new Object[] { item.href });
/*     */       
/* 569 */       Mailbox.SetCalendarItemData main = new Mailbox.SetCalendarItemData();
/* 570 */       Mailbox.SetCalendarItemData[] exceptions = null;
/* 571 */       CalDavClient client = null;
/*     */       try {
/* 573 */         client = getClient();
/*     */       } catch (DavException e) {
/* 575 */         throw ServiceException.FAILURE("error creating CalDAV client", e);
/*     */       }
/*     */       
/* 578 */       CalDavClient.Appointment appt = client.getCalendarData(new CalDavClient.Appointment(item.href, item.etag));
/* 579 */       if (appt.data == null) {
/* 580 */         ZimbraLog.datasource.warn("No appointment found at " + item.href);
/* 581 */         return null;
/*     */       }
/* 583 */       dsItem.md.put("e", appt.etag);
/*     */       try
/*     */       {
/* 586 */         ZCalendar.ZVCalendar vcalendar = ZCalendar.ZCalendarBuilder.build(appt.data);
/* 587 */         List<Invite> invites = Invite.createFromCalendar(this.mbox.getAccount(), null, vcalendar, true);
/* 588 */         if (invites.size() > 1) {
/* 589 */           exceptions = new Mailbox.SetCalendarItemData[invites.size() - 1];
/*     */         }
/* 591 */         pos = 0;
/* 592 */         first = true;
/* 593 */         for (Invite i : invites)
/* 594 */           if (first) {
/* 595 */             main.invite = i;
/* 596 */             first = false;
/*     */           } else {
/* 598 */             Mailbox.SetCalendarItemData scid = new Mailbox.SetCalendarItemData();
/* 599 */             scid.invite = i;
/* 600 */             exceptions[(pos++)] = scid;
/*     */           }
/*     */       } catch (Exception e) { int pos;
/*     */         boolean first;
/* 604 */         ZimbraLog.datasource.warn("Error parsing appointment ", e);
/* 605 */         return null;
/*     */       }
/* 607 */       mi = this.mbox.setCalendarItem(octxt, where.getId(), 0, null, main, exceptions, null, 0L);
/* 608 */       dsItem.itemId = mi.getId();
/* 609 */       dsItem.folderId = mi.getFolderId();
/* 610 */       if (isCreate) {
/* 611 */         DbDataSource.addMapping(ds, dsItem);
/*     */       } else {
/* 613 */         DbDataSource.updateMapping(ds, dsItem);
/*     */       }
/*     */     } else {
/* 616 */       ZimbraLog.datasource.debug("Appointment up to date %s", new Object[] { item.href });
/*     */       try {
/* 618 */         mi = this.mbox.getItemById(octxt, dsItem.itemId, MailItem.Type.UNKNOWN);
/*     */       }
/*     */       catch (MailServiceException.NoSuchItemException se) {
/* 621 */         ArrayList<Integer> deletedIds = new ArrayList();
/* 622 */         deletedIds.add(Integer.valueOf(dsItem.itemId));
/* 623 */         DbDataSource.deleteMappings(ds, deletedIds);
/*     */       }
/*     */     }
/* 626 */     return mi;
/*     */   }
/*     */   
/*     */   private void sync(OperationContext octxt, CalendarFolder cf) throws ServiceException, IOException, DavException {
/* 630 */     Folder syncFolder = cf.folder;
/* 631 */     int lastSync = (int)syncFolder.getLastSyncDate();
/* 632 */     int currentSync = lastSync;
/* 633 */     boolean allDone = false;
/* 634 */     HashMap<Integer, Integer> modifiedFromRemote = new HashMap();
/* 635 */     ArrayList<Integer> deletedFromRemote = new ArrayList();
/*     */     
/*     */ 
/* 638 */     while (!allDone) {
/* 639 */       allDone = true;
/*     */       Iterator i$;
/* 641 */       if (lastSync > 0)
/*     */       {
/* 643 */         List<Integer> deleted = new ArrayList();
/* 644 */         for (Iterator i$ = this.mbox.getTombstones(lastSync).getAllIds().iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 645 */           if (!deletedFromRemote.contains(Integer.valueOf(itemId)))
/*     */           {
/*     */ 
/* 648 */             deleted.add(Integer.valueOf(itemId));
/*     */           }
/*     */         }
/*     */         
/* 652 */         HashSet<Integer> fid = new HashSet();
/* 653 */         fid.add(Integer.valueOf(3));
/* 654 */         List<Integer> trashed = (List)this.mbox.getModifiedItems(octxt, lastSync, MailItem.Type.UNKNOWN, fid).getFirst();
/* 655 */         deleted.addAll(trashed);
/*     */         
/* 657 */         if (!deleted.isEmpty())
/*     */         {
/* 659 */           allDone &= !pushDelete(deleted);
/*     */         }
/*     */         
/*     */ 
/* 663 */         fid.clear();
/* 664 */         fid.add(Integer.valueOf(syncFolder.getId()));
/* 665 */         List<Integer> modified = (List)this.mbox.getModifiedItems(octxt, lastSync, MailItem.Type.UNKNOWN, fid).getFirst();
/* 666 */         for (i$ = modified.iterator(); i$.hasNext();) { int itemId = ((Integer)i$.next()).intValue();
/* 667 */           MailItem item = this.mbox.getItemById(octxt, itemId, MailItem.Type.UNKNOWN);
/* 668 */           if ((!modifiedFromRemote.containsKey(Integer.valueOf(itemId))) || (!((Integer)modifiedFromRemote.get(Integer.valueOf(itemId))).equals(Integer.valueOf(item.getModifiedSequence()))))
/*     */           {
/*     */             try
/*     */             {
/* 672 */               pushModify(item);
/*     */             } catch (Exception e) {
/* 674 */               ZimbraLog.datasource.info("Failed to push item " + item.getId(), e);
/*     */             }
/* 676 */             allDone = false;
/*     */           }
/*     */         }
/*     */       }
/* 680 */       if (cf.ctagMatched) {
/* 681 */         currentSync = this.mbox.getLastChangeID();
/* 682 */         break;
/*     */       }
/*     */       
/*     */ 
/* 686 */       List<RemoteItem> remoteItems = getRemoteItems(syncFolder);
/* 687 */       for (RemoteItem item : remoteItems) {
/* 688 */         MailItem localItem = applyRemoteItem(item, syncFolder);
/* 689 */         if (localItem != null) {
/* 690 */           if (item.status == Status.deleted) {
/* 691 */             deletedFromRemote.add(Integer.valueOf(localItem.getId()));
/*     */           } else
/* 693 */             modifiedFromRemote.put(Integer.valueOf(localItem.getId()), Integer.valueOf(localItem.getModifiedSequence()));
/*     */         }
/*     */       }
/* 696 */       currentSync = this.mbox.getLastChangeID();
/* 697 */       lastSync = currentSync;
/*     */     }
/* 699 */     this.mbox.setSyncDate(octxt, syncFolder.getId(), currentSync);
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/datasource/CalDavDataImport.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */